package fr.jade.fraclite.factory;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.Type;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.IllegalBindingException;
import org.objectweb.fractal.api.control.IllegalLifeCycleException;
import org.objectweb.fractal.api.factory.GenericFactory;
import org.objectweb.fractal.api.factory.InstantiationException;
import org.objectweb.fractal.api.type.ComponentType;
import org.objectweb.fractal.api.type.TypeFactory;
import org.objectweb.fractal.deployment.local.api.IGenericFactoryWithModules;
import org.objectweb.fractal.deployment.local.api.ILoader;
import org.objectweb.fractal.deployment.local.api.IModule;
import org.objectweb.fractal.deployment.local.api.IModuleRepository;
import org.objectweb.fractal.util.Fractal;

import fr.jade.fraclite.deployment.GenericModuleComponent;

/**
 * Provides a basic implementation of the {@link GenericFactory} interface. <br>
 * <br>
 * <b>Requirements</b>
 * <ul>
 * <li>the types used in the {@link #newFcInstance newFcInstance} method must
 * be instances of {@link ComponentType}.</li>
 * <li>the controller descriptors used in the {@link #newFcInstance
 * newFcInstance} method must be strings referencing "true descriptors", which
 * are loaded with the {@link #_this_weaveableL} loader. Here "true descriptors"
 * means controller descriptors as specified in {@link
 * org.objectweb.fractal.julia.asm.ContextClassGenerator}.</li>
 * </ul>
 */

public class BasicGenericFactoryWithModules extends BasicGenericFactory
		implements IGenericFactoryWithModules, BindingController {

	protected ClassLoader loader;

	private IModuleRepository moduleRepo;

	public Component bootstrapComposite;

	private static final String M_REPO = "mr";

	private static final String S_MODULE = "system-1.0.0";

	private IModule systemModule = null;

	// -------------------------------------------------------------------------
	// PUBLIC constructor and weaveableTF are needed for bootstrap
	// -------------------------------------------------------------------------

	public BasicGenericFactoryWithModules() {
		loader = this.getClass().getClassLoader();
	}

	public ILoader getFcLoaderForComponent(Component cmp) {
		// TODO Auto-generated method stub
		return null;
	}

	public void undeployFcComponent(Component cmp) {
		// TODO Auto-generated method stub

	}

	public Component getSystemModule() {
		return moduleRepo.getModuleComponent("system-1.0.0");
	}

	public Component newFcInstance(Type type, Object controllerDesc,
			Object contentDesc, Component moduleComponent)
			throws InstantiationException {
		IModule module;
		try {
			module = (IModule) moduleComponent.getFcInterface(Fractal
					.getNameController(moduleComponent).getFcName());
		} catch (NoSuchInterfaceException e) {
			throw new InstantiationException(e.toString());
		}
		return newFcInstance(type, controllerDesc, contentDesc, module);
	}

	public Component newFcInstance(Type type, Object controllerDesc,
			Object contentDesc, IModule module) throws InstantiationException {

		ClassLoader cLoader;
		if (controllerDesc instanceof String && !controllerDesc.equals("module")) {
			Object[] newControllerDesc = new Object[2];
			newControllerDesc[0] = module;
			newControllerDesc[1] = controllerDesc;
			controllerDesc = newControllerDesc;
		}
		Component result = super.newFcInstance(type, controllerDesc,
				contentDesc);
		bindToModule(contentDesc, result, module);
		return result;
	}

	public Component newFcInstance(final Type type,
			final Object controllerDescLabel, final Object contentDesc)
			throws InstantiationException {
		return newFcInstance(type, controllerDescLabel, contentDesc,
				getSystemModule());
	}

	public Component newFcInstance(Type type, Object controllerDesc,
			Object contentDesc, Object moduleComponentDesc)
			throws InstantiationException {
		return newFcInstance(type, controllerDesc, contentDesc, moduleRepo
				.getModuleComponent(moduleComponentDesc.toString()));
	}

	public void bindFc(String arg0, Object arg1)
			throws NoSuchInterfaceException, IllegalBindingException,
			IllegalLifeCycleException {
		if (arg0.equals(M_REPO)) {
			this.moduleRepo = (IModuleRepository) arg1;
		} else if (arg0.equals(S_MODULE)) {
			this.systemModule = (IModule) arg1;
		} else if (arg0.equals("component")) {
			super.weaveableTF = (TypeFactory) ((Component) arg1)
					.getFcInterface("type-factory");
		}
	}

	public String[] listFc() {
		return new String[] { M_REPO, S_MODULE };
	}

	public Object lookupFc(String arg0) throws NoSuchInterfaceException {
		if (arg0.equals(M_REPO)) {
			return this.moduleRepo;
		} else if (arg0.equals(S_MODULE)) {
			return this.systemModule;
		}
		return null;
	}

	public void unbindFc(String arg0) throws NoSuchInterfaceException,
			IllegalBindingException, IllegalLifeCycleException {
		if (arg0.equals(M_REPO)) {
			this.moduleRepo = null;
		} else if (arg0.equals(S_MODULE)) {
			this.systemModule = null;
		}
	}

	private void bindToModule(final Object contentDesc, Component result,
			IModule module) {
		try {
			if ((contentDesc == null)
					|| (contentDesc instanceof String && contentDesc != "fr.jade.fraclite.deployment.GenericModuleComponent")) {
				Fractal.getBindingController(result).bindFc("module", module);
			}
		} catch (NoSuchInterfaceException e) {
			e.printStackTrace();
		} catch (IllegalBindingException e) {
			e.printStackTrace();
		} catch (IllegalLifeCycleException e) {
			e.printStackTrace();
		}
	}

}
